package com.mrx.bot.telegram.impl;

import com.alibaba.fastjson2.JSON;
import com.mrx.bot.telegram.config.OkhttpConfig;
import com.mrx.bot.telegram.model.BotConfig;
import com.mrx.bot.telegram.utils.BotConfigLoader;
import com.mrx.bot.telegram.utils.WebmToGifConverter;
import com.mrx.bot.telegram.utils.ZipUtils;
import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.telegram.telegrambots.abilitybots.api.bot.AbilityBot;
import org.telegram.telegrambots.abilitybots.api.objects.Ability;
import org.telegram.telegrambots.abilitybots.api.objects.Locality;
import org.telegram.telegrambots.abilitybots.api.objects.Privacy;
import org.telegram.telegrambots.abilitybots.api.toggle.BareboneToggle;
import org.telegram.telegrambots.client.okhttp.OkHttpTelegramClient;
import org.telegram.telegrambots.meta.api.methods.GetFile;
import org.telegram.telegrambots.meta.api.methods.send.SendDocument;
import org.telegram.telegrambots.meta.api.methods.stickers.GetStickerSet;
import org.telegram.telegrambots.meta.api.objects.InputFile;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.message.Message;
import org.telegram.telegrambots.meta.api.objects.stickers.Sticker;
import org.telegram.telegrambots.meta.api.objects.stickers.StickerSet;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.generics.TelegramClient;

import java.io.File;

/**
 * @author Mr.X
 * @since 2025/6/13 20:53
 */
public class StickDownloaderBot extends AbilityBot {

    private static final BotConfig botConfig = BotConfigLoader.getBotConfig();

    private static final String baseDir = botConfig.getDataPath();

    private static final TelegramClient client = new OkHttpTelegramClient(OkhttpConfig.INSTANCE.get(), botConfig.getToken());

    private static final WebmToGifConverter converter = new WebmToGifConverter();

    private static final Logger logger = LoggerFactory.getLogger(StickDownloaderBot.class);

    public StickDownloaderBot() {
        super(client, baseDir + "/" + botConfig.getBotUsername(), new BareboneToggle());
    }

    @Override
    public long creatorId() {
        return botConfig.getCreatorId();
    }

    public String getToken() {
        return botConfig.getToken();
    }

    @Override
    public void consume(Update update) {
        super.consume(update);
        Message message = update.getMessage();
        logger.info("收到消息: {}", JSON.toJSONString(message));
        switch (message) {
            case Message it when it.hasSticker() -> downloadSingleSticker(message.getSticker(), it.getChatId());
            case Message it when it.hasText() -> downloadStickerSet(message);
            default -> logger.info("default do nothing");
        }
    }

    @SuppressWarnings("unused")
    public Ability stickDownloadEntry() {
        return Ability.builder()
                .name("ping")
                .info("检查服务是否在线")
                .locality(Locality.USER)
                .privacy(Privacy.PUBLIC)
                .action(ctx -> silent.send("pong", ctx.chatId()))
                .build();
    }

    @SuppressWarnings("unused")
    public Ability start() {
        return Ability.builder()
                .name("start")
                .info("给出帮助信息")
                .locality(Locality.USER)
                .privacy(Privacy.PUBLIC)
                .action(ctx -> silent.send("直接发送贴纸或者发送贴纸链接, 稍后机器人将会回复贴纸包或者贴纸文件", ctx.chatId()))
                .build();
    }

    @SneakyThrows
    private void downloadStickerSet(Message message) {
        String text = message.getText();
        if (!text.startsWith("https://t.me/addstickers")) {
            return;
        }
        silent.send("正在下载贴纸包, 请稍后", message.getChatId());
        String stickerSetName = text.substring(text.lastIndexOf("/") + 1);
        logger.info("开始下载贴纸包: {}", stickerSetName);
        GetStickerSet getStickerSet = GetStickerSet.builder().name(stickerSetName).build();
        StickerSet stickerSet = client.execute(getStickerSet);
        stickerSet.getStickers().forEach(this::downloadSingleSticker);
        logger.info("贴纸包下载完成, 开始压缩: {}", stickerSetName);
        File srcFile = new File(baseDir, stickerSetName);
        File dstFile = new File(baseDir, stickerSetName + ".zip");
        if (!dstFile.exists()) {
            ZipUtils.zip(srcFile, dstFile);
        }
        // 将 zip 发送给用户
        sendFile(message.getChatId(), dstFile);
        if (srcFile.delete()) {
            logger.info("压缩完毕, 临时文件夹已删除, 结果文件为: {}", dstFile);
        } else {
            logger.info("压缩完毕, 临时文件夹删除失败: {}, 结果文件为: {}", srcFile, dstFile);
        }
    }

    private void downloadSingleSticker(Sticker sticker) {
        downloadSingleSticker(sticker, null);
    }

    @SneakyThrows
    private void downloadSingleSticker(Sticker sticker, Long chatId) {
        if (chatId != null) {
            silent.send("正在下载贴纸, 请稍后", chatId);
        }
        logger.info("开始下载贴纸: {}", JSON.toJSONString(sticker));
        // 根据贴纸类型确定文件扩展名
        File targetFile = getFile(sticker);
        if (targetFile.exists()) {
            logger.info("目标文件已存在, 跳过后续处理: {}", targetFile);
            sendFile(chatId, targetFile);
        } else {
            executeDownload(sticker, chatId, targetFile);
            logger.info("贴纸下载完成: {}", targetFile);
        }
    }

    private void executeDownload(Sticker sticker, Long chatId, File targetFile) throws Exception {
        File gifFile = new File(targetFile.getParent(), FilenameUtils.getBaseName(targetFile.getName()) + ".gif");
        if (gifFile.exists() && sticker.getIsVideo()) {
            logger.info("gif 文件已存在, 跳过后续处理");
            sendFile(chatId, gifFile);
            return;
        }
        if (targetFile.exists()) {
            logger.info("原始文件已存在, 跳过后续处理");
            sendFile(chatId, targetFile);
            return;
        }
        File file = client.downloadFile(client.execute(GetFile.builder().fileId(sticker.getFileId()).build()));
        FileUtils.moveFile(file, targetFile);
        if (sticker.getIsVideo()) {
            logger.info("贴纸下载完成, 准备转换格式");
            webm2Gif(targetFile, gifFile);
            logger.info("格式转换完成");
            if (chatId != null) {
                sendFile(chatId, gifFile.exists() ? gifFile : targetFile);
            }
        } else {
            if (chatId != null) {
                sendFile(chatId, targetFile);
            }
        }
    }

    private File getFile(Sticker sticker) {
        String extension = switch (sticker) {
            case Sticker s when s.getIsVideo() -> ".webm";
            case Sticker s when s.getIsAnimated() -> ".tgs";
            default -> ".webp";
        };
        // 使用 file_unique_id 作为文件名
        String fileName = sticker.getFileUniqueId() + extension;
        // 如果有贴纸集名称，创建对应的子目录
        File targetDir = new File(baseDir);
        if (sticker.getSetName() != null && !sticker.getSetName().isEmpty()) {
            targetDir = new File(baseDir, sticker.getSetName());
            if (!targetDir.exists() && !targetDir.mkdirs()) {
                throw new RuntimeException("创建文件夹失败: " + targetDir.getAbsolutePath());
            }
        }
        return new File(targetDir, fileName);
    }

    private void webm2Gif(File webmFile, File gifFile) throws Exception {
//        ProcessBuilder pb = new ProcessBuilder(
//                "ffmpeg", "-i", webmFile.getAbsolutePath(),
//                "-vf", "fps=23,scale=256:-1:flags=lanczos",
//                "-loop", "0", gifFile.getAbsolutePath(), "-y"
//        );
//        Process process = pb.start();
//        process.waitFor();
        converter.convertWebmToGif(webmFile.getAbsolutePath(), gifFile.getAbsolutePath());
    }

    private void sendFile(Long chatId, File dstFile) throws TelegramApiException {
        SendDocument sendDocument = SendDocument.builder()
                .document(new InputFile(dstFile))
                .chatId(chatId)
                .build();
        client.execute(sendDocument);
    }

}
